﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media.Media3D;
using System.Windows;
using System.Windows.Input;
using Eniux.Windows.ThreeDEngine.AttachObject;

namespace Eniux.Windows.ThreeDEngine.Base.CameraControllers
{
    /// <summary>
    /// 平移控制
    /// </summary>
    internal class PanHandler : MouseGestureHandler
    {
        #region 常量、字段

        /// <summary>
        ///   3D平移点
        /// </summary>
        private Point3D panPoint3D;

        #endregion

        #region 构造析构

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="controller"></param>
        public PanHandler(CameraController controller)
            : base(controller)
        {
        }

        #endregion

        #region 公共方法

        /// <summary>
        /// 触摸操作时，位置点发生改变，引发该事件
        /// </summary>
        /// <param name="e"></param>
        public override void Delta(ManipulationEventArgs e)
        {
            base.Delta(e);
            var thisPoint3D = this.UnProject(e.CurrentPosition, this.panPoint3D, this.Controller.CameraLookDirection);

            if (this.LastPoint3D == null || thisPoint3D == null)
            {
                return;
            }

            Vector3D delta3D = this.LastPoint3D.Value - thisPoint3D.Value;
            this.Pan(delta3D);

            this.LastPoint = e.CurrentPosition;
            this.LastPoint3D = this.UnProject(e.CurrentPosition, this.panPoint3D, this.Controller.CameraLookDirection);
        }

        /// <summary>
        /// 平移视场
        /// </summary>
        /// <param name="delta">delta</param>
        public void Pan(Vector3D delta)
        {
            if (!AttachCamera.GetIsPanEnabled(Controller))
            {
                return;
            }
            if (this.CameraMode == CameraMode.FixedPosition)
            {
                return;
            }

            this.CameraPosition += delta;
        }

        /// <summary>
        /// 以2D方式平移相机
        /// </summary>
        /// <param name="delta">delta</param>
        public void Pan(Vector delta)
        {
            var mousePoint = this.LastPoint + delta;

            var thisPoint3D = this.UnProject(mousePoint, this.panPoint3D, this.Controller.CameraLookDirection);

            if (this.LastPoint3D == null || thisPoint3D == null)
            {
                return;
            }

            Vector3D delta3D = this.LastPoint3D.Value - thisPoint3D.Value;
            this.Pan(delta3D);

            this.LastPoint3D = this.UnProject(mousePoint, this.panPoint3D, this.Controller.CameraLookDirection);

            this.LastPoint = mousePoint;
        }

        /// <summary>
        /// 当操作开始时，引发该事件
        /// </summary>
        /// <param name="e"></param>
        public override void Started(ManipulationEventArgs e)
        {
            base.Started(e);
            this.panPoint3D = this.Controller.CameraTarget;
            if (this.MouseDownNearestPoint3D != null)
            {
                this.panPoint3D = this.MouseDownNearestPoint3D.Value;
            }

            this.LastPoint3D = this.UnProject(this.MouseDownPoint, this.panPoint3D, this.Controller.CameraLookDirection);
        }

        #endregion

        #region 方法
 
        /// <summary>
        /// 是否执行平移
        /// </summary>
        /// <returns></returns>
        protected override bool CanExecute()
        {
            return AttachCamera.GetIsPanEnabled(Controller);
        }

        /// <summary>
        /// 获取平移光标
        /// </summary>
        /// <returns>光标</returns>
        protected override Cursor GetCursor()
        {
            return AttachCamera.GetPanCursor(Controller);
        }

        /// <summary>
        /// 当惯性开始时，引发该事件
        /// </summary>
        /// <param name="elapsedTime">单位毫秒</param>
        protected override void OnInertiaStarting(int elapsedTime)
        {
            var speed = (this.LastPoint - this.MouseDownPoint) * (40.0 / elapsedTime);
            this.Controller.AddPanForce(speed.X, speed.Y);
        }

        #endregion
    }
}
